package com.eolwral.osmonitor;
import java.text.DecimalFormat;
import java.util.ArrayList;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.database.sqlite.SQLiteDatabase;
import android.media.AudioManager;
import android.net.TrafficStats;
import android.net.wifi.WifiManager;
import android.os.BatteryManager;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.util.Log;
import android.widget.RemoteViews;
import com.eolwral.osmonitor.preferences.Preferences;
import com.eslab.osmonitor.providerDB.DatabaseHelper;
import com.eslab.osmonitor.utility.StandardDeviation;
public class OSMonitorService extends Service
{
private static final String TAG = "OSmonitor";
private static final int NOTIFYID = 20091231; //통지의 아이디 값이다.
private static final int POWERMODELID = 20110716; //power model 전용 통지 ID이다.
private static final int DEBUGNOTIFYID = 20111226; //debug용 이다.
private static int battLevel = 0; // percentage, or -1 for unknown
private static int temperature = 0;
private static int voltage = 0;
private static int useColor = 0;
private static boolean useCelsius = true;
private static boolean plugState = false; //플러긴 상태에 따라서 PowerModel chunk를 수집할지를 결정하기 위해서 상태를 저장한다.
private static boolean chunkSkip = false; //맨 처음 시작은 청크를 기록 하지않는다. 그 유무는 플러긴으로 구별된다.
private static int chunkSkipCount = 0;
private NotificationManager serviceNM = null;
private Notification serviceNotify = null;
private Notification powerModelNotify = null;
private Notification debugNotify = null;
private Context serviceContext = null;
private double mBatteryCapacity = 0.015; //베터리 용량이다.
private boolean TimeUpdate = false;
private int UpdateInterval = 1;
private static JNIInterface JNILibrary = JNIInterface.getInstance();;
private static OSMonitorService single = null;
private CPowerModel mPowerModel; //나의 Power Model 관련 객체 이다.
private int mOldPowerCap; //이전의 battery cap의 수치 값이다.
private int mNewPowerCap; //현재의 battery cap의 수치 값이다.
private ContentResolver mContentResolver;
private PowerManager mPowermanager; //Power Manager의 객체이다.
private WakeLock mWakeLock; //Wake Lock 객체이다.
private AudioManager mAudioManager;
//Power Model 값을 연산해서 DB에 삽입하기위한 것들이다.
//private boolean OldCapCondition = false;
private double avgVoltage = 0.0;
private double avgPower = 0.0;
private double avgCPULoad = 0.0;
private double sdCPULoad = 0.0;
private double avgCPUFrequency = 0.0;
private double sdCPUFrequency = 0.0;
private double avgLEDTime = 0.0;
private double sdLEDTime = 0.0;
private double avgLEDBright = 0.0;
private double sdBright = 0.0;
private double avgWifiOnTime = 0.0;
private double avgWifiPacketRate = 0.0;
private int debugCount = 0; // 디버깅을 위해서 만든 것이다.
private double LedOn = 0.0; //power 값을 계산할때 led값을 반영할지에 대한 여부이다.
//wifi interface의 state를 알아오기 위한 정보 이다.
private WifiManager wifiManager;
long lastTransmitPackets;
long lastReceivePackets;
//계산한 Power 값을 저장하고 있다.
public ArrayList<Double> mPowerValue;
//Model값을 가지고있는 class이다.
CPowerModelValue mOPowerModelValue;
//java proc/stat를 읽기위해서
private CpuUsage mOCpuUsage;
private int AverageConditionBit = 0;
//main activity에서 동작 시키기 위함 이다.
public static OSMonitorService getInstance()
{
if(single != null)
return single;
return null;
}
public class OSMonitorBinder extends Binder
{
OSMonitorService getService()
{
return OSMonitorService.this;
}
}
private final IBinder mBinder = new OSMonitorBinder();
private static DecimalFormat MemoryFormat = new DecimalFormat(",000");
private static int cpuLoad = 0;
//profile을 해서 power를 계산하는 handler이다.
private Handler mHandler = new Handler();
private Runnable mRefresh = new Runnable()
{
@Override
public void run() {
double mWifiPower = 0.0;
int bright_level=0;
cpuLoad = JNILibrary.GetCPUUsageValue();
if(cpuLoad < 20)
serviceNotify.iconLevel = 1+useColor*100;
else if(cpuLoad < 40)
serviceNotify.iconLevel = 2+useColor*100;
else if(cpuLoad < 60)
serviceNotify.iconLevel = 3+useColor*100;
else if(cpuLoad < 80)
serviceNotify.iconLevel = 4+useColor*100;
else if(cpuLoad < 100)
serviceNotify.iconLevel = 5+useColor*100;
else
serviceNotify.iconLevel = 6+useColor*100;
//java proc/stat
mOCpuUsage.readStats();
//notification에 표시하는 정보들을 기록한다.
String maininfo = "CPU: "+cpuLoad+"% , "+mOCpuUsage.getTotalCPUInt()+"%, "
+"MEM:"+MemoryFormat.format(JNILibrary.GetMemBuffer()+JNILibrary.GetMemCached()+JNILibrary.GetMemFree())+ "K";
String extendinfo = "";
if(useCelsius)
extendinfo = " Battery: "+battLevel+"%"+" ("+temperature/10+"°C)";
else
extendinfo = " Battery: "+battLevel+"%"+" ("+((int)temperature/10*9/5+32)+"°F)";
serviceNotify.setLatestEventInfo(serviceContext, maininfo,
extendinfo, serviceNotify.contentIntent);
/* 기존 소스 주석임 제거시 에러 발생.
serviceNotify.contentView.setTextViewText(R.id.StatusBarCPU, "CPU: "+cpuLoad+"%");
serviceNotify.contentView.setTextViewText(R.id.StatusBarMEM, "MEM: "+MemoryFormat.format(JNILibrary.GetMemBuffer()+JNILibrary.GetMemCached()+JNILibrary.GetMemFree())+ "K");
if(useCelsius)
serviceNotify.contentView.setTextViewText(R.id.StatusBarBAT, "BAT: "+battLevel+"%"+" ("+temperature/10+"°C)");
else
serviceNotify.contentView.setTextViewText(R.id.StatusBarBAT, "BAT: "+battLevel+"%"+" ("+((int)temperature/10*9/5+32)+"°F)");
*/
//App-Widget에 대한 동작 부분을 설정한다.
//출력할 내뇽을 RemoteViews로 만들어서 관리자에게 전달해야 Widget이 갱신되어 진다.
RemoteViews views = new RemoteViews(serviceContext.getPackageName(), R.layout.battery_widget);
views.setTextViewText(R.id.gauge, "" + cpuLoad);
AppWidgetManager wm = AppWidgetManager.getInstance(OSMonitorService.this);
ComponentName widget = new ComponentName(serviceContext, BatteryWidget.class);
wm.updateAppWidget(widget, views);
try
{
serviceNM.notify(NOTIFYID, serviceNotify);
} catch(Exception e) {}
//스크린 여부에따라 연산에 적용시킬 껀지를 판별 한다.
if(mPowermanager.isScreenOn()){
LedOn = 1.0;
bright_level =Settings.System.getInt(mContentResolver, Settings.System.SCREEN_BRIGHTNESS, -1);
}
else{
LedOn = 0.0;
}
//WIFI chunk를 수집한다.
//Wifi Interface가 활성화 상태인지 부터 체크 한다.
if(wifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLED){
mPowerModel.mWIFITActivityTime++;
long transmitPackets = TrafficStats.getTotalTxPackets();
long receivePackets = TrafficStats.getTotalRxPackets();
long lastPackets = receivePackets + transmitPackets -
lastReceivePackets - lastTransmitPackets;
//chunk에 packet Rate를 누적 시킨다.
mPowerModel.mWIFIPacketRate += lastPackets; //총 패킷을 누적 시킨다.
mPowerModel.mSDWiFiPacketRate.add((double)lastPackets); //표준편차를 계산하기 위함 이다.
//wifi Power 정보를 계산한다.
if( lastPackets >= mOPowerModelValue.mWifiMaxCondition){
mWifiPower = mOPowerModelValue.mWifiMax;
}
else {
mWifiPower = mOPowerModelValue.mWiFiOn+
lastPackets * mOPowerModelValue.mWiFiModel_B +
Math.pow(lastPackets,2)*mOPowerModelValue.mWiFiModel_A;
}
//Packets 정보를 갱신 한다.
lastTransmitPackets = transmitPackets;
lastReceivePackets = receivePackets;
}
//Power Model 연산을 한다.
/* mOPowerModelValue.mCurrentPower_typeFour.add(
LedOn * mOPowerModelValue.mBrightCoeff*bright_level + mOPowerModelValue.mBrightConst +
mOPowerModelValue.mCPUUageMulTypeFour*JNILibrary.GetCPUUsageValue() +
mOPowerModelValue.mCPUUageSumTypeFour +
mWifiPower);*/
mPowerValue.add(
LedOn * mOPowerModelValue.mBrightCoeff*bright_level + mOPowerModelValue.mBrightConst +
mOPowerModelValue.mCPUUageMulTypeFour*JNILibrary.GetCPUUsageValue() +
mOPowerModelValue.mCPUUageSumTypeFour +
mWifiPower);
//current Sensor와 비교하기 위한 루틴 50초마다 평균을 내어주기 위함 이다.
/*AverageConditionBit++;
if(AverageConditionBit >= 50){
double sumFour = 0.0;
double avgFour = 0.0;
for(int i =0; i<mOPowerModelValue.mCurrentPower_typeFour.size(); i++){
sumFour += mOPowerModelValue.mCurrentPower_typeFour.get(i);
}
avgFour = sumFour / 50.0;
mPowerValue.add(avgFour);
//초기화 루틴
AverageConditionBit = 0 ;
mOPowerModelValue.CurrentPowerClear(); //다시 power값을 줙 시켜야 하므로
}*/
mHandler.postDelayed(mRefresh, UpdateInterval * 1000);
}
};
//PowerModel을 생성하는 handler이다.
private Handler mPMGeneratorHandler = new Handler();
private Runnable mPowerModelGenerator = new Runnable()
{
@Override
public void run() {
//plug 상태가 충전중이 아닐 때만 동작 하도록 한다.
if(plugState){
mNewPowerCap = battLevel; //현재 Battery cap을 읽는다.(1초에 한번씩)
//debug
/*if(debugCount > 10){
debugCount = 0;
battLevel--;
}
debugCount ++;*/
//Battery cap에 변화가 없다면 누적 연산을 지속 한다.
if(mOldPowerCap == mNewPowerCap){
//계산을 위해서 누적 하는 부분이다.
mPowerModel.mCount++;
mPowerModel.mVoltage += voltage;
mPowerModel.mSDVoltage.add(voltage); //표준편차 계산을 위해서 리스트 삽입
//CPU
mPowerModel.mCPULoad += JNILibrary.GetCPUUsageValue();
mPowerModel.mSDCPULoad.add(JNILibrary.GetCPUUsageValue());//표준편차 계산을 위해서 리스트 삽입
mPowerModel.mCPUFrequency +=JNILibrary.GetProcessorScalCur();
mPowerModel.mSDCPUFrequency.add(JNILibrary.GetProcessorScalCur()); //표준편차 계산을 위해서 리스트 삽입
//if(mPowerModel.mLEDState){
if(mPowermanager.isScreenOn()){
mPowerModel.mLEDActivityTime++;
mPowerModel.mLEDBrightness +=
Settings.System.getInt(mContentResolver, Settings.System.SCREEN_BRIGHTNESS, -1);
mPowerModel.mSDLEDBright.add(
Settings.System.getInt(mContentResolver, Settings.System.SCREEN_BRIGHTNESS, -1));
//표준편차 계산을 위해서 리스트 삽입
}
//WIFI chunk를 수집한다.
//Wifi Interface가 활성화 상태인지 부터 체크 한다.
if(wifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLED){
mPowerModel.mWIFITActivityTime++;
long transmitPackets = TrafficStats.getTotalTxPackets();
long receivePackets = TrafficStats.getTotalRxPackets();
long lastPackets = receivePackets + transmitPackets -
lastReceivePackets - lastTransmitPackets;
//chunk에 packet Rate를 누적 시킨다.
mPowerModel.mWIFIPacketRate += lastPackets; //총 패킷을 누적 시킨다.
mPowerModel.mSDWiFiPacketRate.add((double)lastPackets); //표준편차를 계산하기 위함 이다.
//Packets 정보를 갱신 한다.
lastTransmitPackets = transmitPackets;
lastReceivePackets = receivePackets;
}
//3G
//GPS
//AUDIO 동작 중이라면 오디오 기록 시간을 증가 시킨다.
if(mAudioManager.isMusicActive()){
mPowerModel.mAUDIOActivityTime++;
}
//통지에 출력을 하는 부분이다.
String maininfo = String.format("L:%.0f R:%.0f B:%.0f F:%.0f",
mPowerModel.mCPULoad,mPowerModel.mLEDActivityTime,mPowerModel.mLEDBrightness,mPowerModel.mCPUFrequency);
String extendinfo = "";
extendinfo = String.format("Time:%.0f AvgV:%.2f AvgP:%.2f", mPowerModel.mCount,avgVoltage,avgPower);
serviceNotify.setLatestEventInfo(serviceContext, maininfo,
extendinfo, serviceNotify.contentIntent);
try
{
serviceNM.notify(POWERMODELID, serviceNotify);
} catch(Exception e) {}
}
else if(mOldPowerCap > mNewPowerCap){
//Power Model의 첫번째 청크는 Skip하기 위함이다. 왜냐하면 battery 1% charge가 올바르지 않기 때문이다.
if(chunkSkip){
//전력을 계산해서 청크로 DB에 기록한다.
avgVoltage = ((double)mPowerModel.mVoltage/mPowerModel.mCount)/1000;
avgPower = ((mBatteryCapacity*3600*avgVoltage)/mPowerModel.mCount)*1000;
avgCPULoad = (double)mPowerModel.mCPULoad/mPowerModel.mCount;
avgCPUFrequency = mPowerModel.mCPUFrequency / mPowerModel.mCount;
//잘못된 계산 결과를 맊기 위함이다.
if(mPowerModel.mLEDActivityTime == 0){
avgLEDTime = 0;
avgLEDBright = 0;
}
else{
avgLEDTime = (double)mPowerModel.mLEDActivityTime / mPowerModel.mCount;
avgLEDBright = (double)mPowerModel.mLEDBrightness /mPowerModel.mLEDActivityTime; // led가 가동 했을 때만 밝기를 계산하기 때문에.
}
//wifi 부분을 계산한다.
avgWifiOnTime = (double)mPowerModel.mWIFITActivityTime / mPowerModel.mCount;
avgWifiPacketRate = (double)mPowerModel.mWIFIPacketRate / mPowerModel.mCount;
//표준편차를 계산 한다.
double SDCPULoad = mPowerModel.mSDCPULoad.EvaluateSD();
double SDCPUFreq = mPowerModel.mSDCPUFrequency.EvaluateSD();
double SDLEDBright = mPowerModel.mSDLEDBright.EvaluateSD();
double SDVoltage = mPowerModel.mSDVoltage.EvaluateSD();
double SDPacketRate = mPowerModel.mSDWiFiPacketRate.EvaluateSD();
/*
//debug notification을 출력하는 부분이다. wifi packet rate를 조사사기 위함이다.
String maininfo = String.format("debug message");
String extendinfo = "";
extendinfo = mPowerModel.mSDWiFiPacketRate.printItemList();
debugNotify.setLatestEventInfo(serviceContext, maininfo,
extendinfo, debugNotify.contentIntent);
try
{
serviceNM.notify(DEBUGNOTIFYID, debugNotify);
} catch(Exception e) {}
*/
//DB에 기록을 하는 코드 이다.
ContentValues values = new ContentValues();
values.put("power", avgPower);
values.put("cpu_load_avg", avgCPULoad);
values.put("cpu_load_sd",SDCPULoad);
values.put("cpu_freq_avg", avgCPUFrequency);
values.put("cpu_freq_sd", SDCPUFreq);
values.put("led_time_avg", avgLEDTime);
values.put("led_bright_avg", avgLEDBright);
values.put("led_bright_sd", SDLEDBright);
values.put("count", mPowerModel.mCount);
values.put("start_point",mOldPowerCap);
values.put("end_point",mNewPowerCap);
values.put("voltage_avg",avgVoltage);
values.put("voltage_sd",SDVoltage);
values.put("wifi_on_time", avgWifiOnTime);
values.put("wifi_avg_packet_rate", avgWifiPacketRate);
values.put("wifi_sd_packet_rate", SDPacketRate);
insertPowerModelData(values);
mOldPowerCap = mNewPowerCap; // 값을 다시 같게 해준다.(낮아진 값으로)
mPowerModel.Clear();
}
else{
chunkSkip = true; // 처음 시작할떄 1%의 한 청크만 스킵하기 위함이다.
chunkSkipCount = 1; // 리시버에 의해서 계속 chunkSkip이 false가 되지 않게 하기 위함이다.
mOldPowerCap = mNewPowerCap; // 값을 다시 같게 해준다.(낮아진 값으로)
mPowerModel.Clear(); // 클리어는 필수다.
}
}
else{
//이경우는 NewPowerCap이 Old보다 높은 경우 이다.
//충전에 의해서 높아진경우.
mOldPowerCap = mNewPowerCap; //값을 맞춰주어서 정확히 동작하도록 만들어준다.
}
}
Log.d(TAG, "Old " + mOldPowerCap + " New " + mNewPowerCap + "PlugState"+plugState);
mPMGeneratorHandler.postDelayed(mPowerModelGenerator,1000);
}
};
//DB에 데이터를 삽입하는 함수이다.
public boolean insertPowerModelData(ContentValues values){
Log.d(TAG, "insertBatteryData: " + values);
DatabaseHelper mOpenHelper = null;
SQLiteDatabase db = null;
boolean rc = true;
try {
mOpenHelper = new DatabaseHelper(this);
db = mOpenHelper.getReadableDatabase();
Long rowid = db.insert(DatabaseHelper.POWER_TABLE, "PowerModel", values);
if (rowid < 0) {
Log.e(TAG, "database insert failed: " + rowid);
rc = false;
} else {
Log.d(TAG, "sample collected, rowid=" + rowid);
}
} catch (Exception e) {
Log.e(TAG, "database exception");
rc = false;
}
if (db != null) db.close();
if (mOpenHelper != null) mOpenHelper.close();
return rc;
}
@Override
public void onCreate() {
serviceNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
InitNotification();
Notify();
InitalPowerModel(); //Power Model 관련 초기화를 수행 한다
single = this;
mOCpuUsage = new CpuUsage(); //java proc/stat
mOPowerModelValue = new CPowerModelValue(); // Power Model 값이다.
mOPowerModelValue.intialModel();
mPowerValue = new ArrayList<Double>(); //Power 연산 값을 저장하기 위한 Array List이다.
wifiManager = (WifiManager)getSystemService(Context.WIFI_SERVICE); // wifi Interface 객체를 얻어온다.
initWifivariable(); // Wifi chunk관련 변수들의 초기화를 담당 한다.
}
public void initWifivariable(){
lastTransmitPackets = TrafficStats.getTotalTxPackets();
lastReceivePackets = TrafficStats.getTotalRxPackets();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Disable();
//WakeLock을 제거한다.
mWakeLock.release();
//debug profile != PowerModel 핸들러를 제거 한다.
mPMGeneratorHandler.removeCallbacks(mPowerModelGenerator);
//통지를 제거한다.
serviceNM.cancel(POWERMODELID);
}
public void Notify()
{
Enable();
}
//Power Model을 동작하게 하는데 들어가는 각종 초기화 작업이다.
public void InitalPowerModel(){
mPowerModel = new CPowerModel(); //Power model 객체
//battery cap
mNewPowerCap = 0;
mOldPowerCap = 0;
mContentResolver = getContentResolver(); //시스템 설정값을 알아오기위해 컨텐트리졸버를 얻어와야한다.
//Wake Lock를 얻어온다.
mPowermanager = (PowerManager) getSystemService(Context.POWER_SERVICE); //파워 매니저를 얻어온다. (스크린 상태를 조사한다.)
mWakeLock = mPowermanager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WakeAlways"); //WakeLock을 만들어 낸다.
mWakeLock.acquire(); // sleep mode에서도 CPU를 활성화 시키기위한 WakeLock이다.
mAudioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE); //오디오 매니저를 얻어온다. (오디오 상태를 조사하기 위해서)
//debug profile러의 속도를 향상 시키기위해서 CHunk수집 기능을 제거한다.
mPMGeneratorHandler.postDelayed(mPowerModelGenerator,1000); // PowerModel 핸드러를 시작 시킨다.
}
private void Enable()
{
//지속적으로 Enable이 호출 되기 때문에 필터의 등록 여부를 다시 확인한다.
//설정을 바궜다고해서 등록한 필터를 또 등록할 필요는 없기 때문이다.
if(!mRegistered)
{
// 동적으로 리시버와 필터를 등록해 준다.
IntentFilter filterScreenON = new IntentFilter(Intent.ACTION_SCREEN_ON);
registerReceiver(mReceiver, filterScreenON);
IntentFilter filterScreenOFF = new IntentFilter(Intent.ACTION_SCREEN_OFF);
registerReceiver(mReceiver, filterScreenOFF);
//리시버가 등록 되었는지 여부를 나타내는 플래그 이다.
mRegistered = true;
}
// load settings
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
try {
UpdateInterval = Integer.parseInt(settings.getString(Preferences.PREF_UPDATE, "2"));
} catch(Exception e) {}
//프리퍼런스 속성에 의존된다.
if(settings.getBoolean(Preferences.PREF_CPUUSAGE, false))
{
//일단 처음엔 등록이 안되었기 때문에 핸들러 메시지를 한번 날려주는 형태이다.
/*
*이걸 하는 이유는 Acitivyㅇ서 프리퍼런스나. 리쥼에 의해서 다시 재시작 됬을떄
*설정값이 바뀌었을수도있기 때문에 Enaable을 한번 더해준다. 근데 이미 서비스가 실행 중이라면
*서비스 핸들러가 중복해서 2개가 돌아가는것이기 때문에 따라서 TimeUpdate를 가지고 구분하게 되어진다.
*/
if(TimeUpdate == false)
{
JNILibrary.doCPUUpdate(1);
mHandler.postDelayed(mRefresh, UpdateInterval * 1000);
TimeUpdate = true; // 핸들러 메시지가 한번 전송 되었기 때문에 true로 값이 바뀐다.
}
}
else
{
//동작하고 있으면 제거해 준다.
if(TimeUpdate == true)
{
// modi = 0 ->1
JNILibrary.doCPUUpdate(1);
mHandler.removeCallbacks(mRefresh);
TimeUpdate = false;
}
serviceNotify.iconLevel = 0;
serviceNM.notify(NOTIFYID, serviceNotify);
}
useCelsius = settings.getBoolean(Preferences.PREF_TEMPERATURE, true);
useColor = Integer.parseInt(settings.getString(Preferences.PREF_STATUSBARCOLOR, "0"));
startBatteryMonitor();
}
private void Disable()
{
serviceNM.cancel(NOTIFYID);
if(TimeUpdate)
{ // 0 -> 1
JNILibrary.doCPUUpdate(1);
mHandler.removeCallbacks(mRefresh);
TimeUpdate = false;
}
if(mRegistered)
{
unregisterReceiver(mReceiver);
mRegistered = false;
}
stopBatteryMonitor();
}
private void startBatteryMonitor()
{
IntentFilter battFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
registerReceiver(battReceiver, battFilter);
}
private void stopBatteryMonitor()
{
unregisterReceiver(battReceiver);
}
private static BroadcastReceiver battReceiver = new BroadcastReceiver()
{
public void onReceive(Context context, Intent intent) {
int rawlevel = intent.getIntExtra("level", -1);
int scale = intent.getIntExtra("scale", -1);
int plug;
voltage = intent.getIntExtra(BatteryManager.EXTRA_VOLTAGE, 0); //베터리의 전압을 조사한다.
temperature = intent.getIntExtra("temperature", -1);
plug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0); //외부 전원이 연결 되어있는 지를 조사한다. (e.g : AC, USB)
// 베터리 충전 상태를 구분 한다. 이 상태에 따라서 Chunk를 모을지 안모을지를 결정한다.
switch (plug) {
case BatteryManager.BATTERY_PLUGGED_AC:
plugState = false;
chunkSkip = false;
chunkSkipCount = 0; //다시 신뢰할수 없는 상태로 돌아감.
break;
case BatteryManager.BATTERY_PLUGGED_USB:
plugState = false;
chunkSkip = false;
chunkSkipCount = 0; //다시 신뢰할수 없는 상태로 돌아감.
break;
default:
//초기화시에 핸들러가 등록되어 지지않고 플러긴 상태에 따라서 핸들러를 다르게 등록 시킨다.
plugState = true;
//이 구문이 계속 수행되어지기 때문에 0이라면 false를 유지시켜줘야한다. 1이라면 더이상 false면 안된다.
//왜냐하면 처음 딱 한번만 Skip해야 하기 때문이다.
if(chunkSkipCount == 0) chunkSkip = false; // 첫번째를 무시하기 위함이다.
break;
}
if (rawlevel >= 0 && scale > 0) {
//debug;
battLevel = (rawlevel * 100) / scale;
}
}
};
private boolean mRegistered = false;
//sleep mode 일때 쓸때 없는 동작을 막아 주기위한 리시버이다.
//즉 시스템에서 ACTION_SCREEN_OFF라고 메시지가 날라온다면 그때 모든 작업을 정지 시킨다.
private BroadcastReceiver mReceiver = new BroadcastReceiver()
{
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals(Intent.ACTION_SCREEN_OFF))
{
mPowerModel.mLEDState = false; // screen off를 나타낸다.
if(TimeUpdate)
{ //0->1
/*
* doCPUUpdate는 native 함수에서 cpu_usage_bg를 결정한다
* 즉 1이 설정되면 cpu_usage관련 함수들이 동작을 한다.
* e.g : cpu_refresh(), cpu_refresh_usage(), misc_dump_processor(), mem_dump()
* cpu_usage_bg가 0 라면 update_process가 1일때 즉, Activity가 프로세스 Activity일때 만 위의 매서드들이
* 동작하게 되어 진다.
*/
JNILibrary.doCPUUpdate(1);
//mHandler.removeCallbacks(mRefresh);
TimeUpdate = false;
}
}
else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON))
{
mPowerModel.mLEDState = true; // screen on을 나타낸다.
// load settings
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context);
if(settings.getBoolean(Preferences.PREF_CPUUSAGE, false))
{
if(TimeUpdate == false)
{
JNILibrary.doCPUUpdate(1);
//mHandler.postDelayed(mRefresh, UpdateInterval * 1000);
TimeUpdate = true;
}
}
}
}
};
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
//통지 초기화
private void InitNotification()
{
int thisIcon = R.anim.statusicon; // icon from resources
long thisTime = System.currentTimeMillis(); // notification time
serviceContext = this;
CharSequence tickerText = getResources().getString(R.string.bar_title);
CharSequence contentText = getResources().getString(R.string.notify_text);
CharSequence contentTextSecond = getResources().getString(R.string.service_text);
CharSequence contentTitle = getResources().getString(R.string.app_title);
CharSequence contentTitleSecond = getResources().getString(R.string.service_title);
serviceNotify = new Notification(thisIcon, tickerText, thisTime);
serviceNotify.flags |= Notification.FLAG_NO_CLEAR|Notification.FLAG_ONGOING_EVENT;
//RemoteViews contentView = new RemoteViews(getPackageName(), R.layout.notificationlayout);
//contentView.setImageViewResource(R.id.image, R.drawable.appicon);
//contentView.setTextViewText(R.id.StatusBarCPU, "Wait..");
//serviceNotify.contentView = contentView;
Intent notificationIntent = new Intent(this, OSMonitor.class);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
serviceNotify.contentIntent = contentIntent;
serviceNotify.setLatestEventInfo(this, contentTitle, contentText, contentIntent);
serviceNM.notify(NOTIFYID, serviceNotify);
//Power Model Notification이다.
powerModelNotify = new Notification(thisIcon, tickerText, thisTime);
powerModelNotify.flags |= Notification.FLAG_NO_CLEAR|Notification.FLAG_ONGOING_EVENT;
powerModelNotify.contentIntent = contentIntent;
powerModelNotify.setLatestEventInfo(this, contentTitleSecond, contentTextSecond, contentIntent);
serviceNM.notify(POWERMODELID, powerModelNotify);
//debug Notify이다.
debugNotify = new Notification(thisIcon, tickerText, thisTime);
debugNotify.flags |= Notification.FLAG_NO_CLEAR|Notification.FLAG_ONGOING_EVENT;
debugNotify.contentIntent = contentIntent;
debugNotify.setLatestEventInfo(this, contentTitleSecond, contentTextSecond, contentIntent);
serviceNM.notify(DEBUGNOTIFYID, debugNotify);
}
//Power Model 값을 보유하고있으며, 계산 결과를 누적시키는 클래스이다.
class CPowerModelValue{
public ArrayList<Double> mCurrentPower;
public ArrayList<Double> mCurrentPower_typeOne;
public ArrayList<Double> mCurrentPower_typeTwo;
public ArrayList<Double> mCurrentPower_typeThree;
public ArrayList<Double> mCurrentPower_typeFour;
public ArrayList<Double> mCPUUage;
public ArrayList<Double> mBright;
public double mLEDPower = 0.0;
public double mCPUPower = 0.0;
//regression value
public double mBrightTypeOne;
public double mBrightTypeTwo;
public double mBrightTypeThree;
public double mBrightConst;
public double mBrightCoeff;
public double mCPUUageMulTypeOne;
public double mCPUUageSumTypeOne;
public double mCPUUageMulTypeTwo;
public double mCPUUageSumTypeTwo;
public double mCPUUageMulTypeThree;
public double mCPUUageSumTypeThree;
public double mCPUUageMulTypeFour;
public double mCPUUageSumTypeFour;
public double mWiFiOn;
public double mWiFiModel_A;
public double mWiFiModel_B;
public double mWifiMax;
public int mWifiMaxCondition;
public CPowerModelValue(){
mCPUUage = new ArrayList<Double>();
mBright = new ArrayList<Double>();
mCurrentPower = new ArrayList<Double>();
mCurrentPower_typeOne = new ArrayList<Double>();
mCurrentPower_typeTwo = new ArrayList<Double>();
mCurrentPower_typeThree = new ArrayList<Double>();
mCurrentPower_typeFour = new ArrayList<Double>();
}
public void intialModel(){
mBrightConst = 285.036; // chunk very high 압축 (45개)
mBrightCoeff = 2.281;
mCPUUageMulTypeFour = 7.080; // chunk very high 압축
mCPUUageSumTypeFour = 131.495;
mWiFiModel_A = 0.0525;
mWiFiModel_B = 2.3181;
mWiFiOn = 23.764;
mWifiMax = 890.704;
mWifiMaxCondition = 109;
}
public void ModelClear(){
mCPUUage.clear();
mBright.clear();
}
public void CurrentPowerClear(){
mCurrentPower_typeFour.clear();
}
}
//청크를 구성하기 전에 데이터를 누적하기위한 데이터 Class이다.
class CPowerModel{
public boolean mLEDState;
public double mLEDActivityTime;
public double mLEDBrightness;
public double mCPULoad;
public double mCPUFrequency;
public boolean mGPSState;
public double mGPSActivityTime;
public double mCellularRx;
public double mCellularTx;
public double mCellularActivityTime;
public double mWIFIPacketRate;
public double mWIFIRx;
public double mWIFITx;
public double mWIFITActivityTime;
public boolean mAUDIOState;
public double mAUDIOActivityTime;
public double mCount;
public double mVoltage;
//표준편차를 구하기 위함 객체들
public StandardDeviation mSDLEDBright;
public StandardDeviation mSDCPULoad;
public StandardDeviation mSDCPUFrequency;
public StandardDeviation mSDCellularRx;
public StandardDeviation mSDCellularTx;
public StandardDeviation mSDWIFIRx;
public StandardDeviation mSDWIFITx;
public StandardDeviation mSDWiFiPacketRate;
public StandardDeviation mSDVoltage;
public CPowerModel(){
mLEDState = true; //시작할때는 어차피 프로그램이 한번은 켜지기 때문에 화면이 켜진 상태가 맞다.
mLEDActivityTime = 0.0;
mLEDBrightness = 0.0;
mCPULoad = 0.0;
mCPUFrequency = 0.0;
mGPSState = false; //장치가 켜졌다고해서 활성화가 된것이 아니기 때문에 지금 상태가 맞을 것이다.
mGPSActivityTime = 0.0;
mCellularRx = 0.0;
mCellularTx = 0.0;
mCellularActivityTime = 0.0;
mWIFIPacketRate = 0.0;
mWIFIRx = 0.0;
mWIFITx = 0.0;
mWIFITActivityTime = 0.0;
mAUDIOState = false; //오디오의 경우 애매한 부분이다.
mAUDIOActivityTime = 0.0;
mCount = 0.0;
mVoltage = 0.0;
//표준편차를 구하기 위함 객체들의 초기화 코드이다.
mSDLEDBright = new StandardDeviation(StandardDeviation.DOUBLE);
mSDCPULoad = new StandardDeviation(StandardDeviation.DOUBLE);
mSDCPUFrequency = new StandardDeviation(StandardDeviation.DOUBLE);
mSDCellularRx = new StandardDeviation(StandardDeviation.DOUBLE);
mSDCellularTx = new StandardDeviation(StandardDeviation.DOUBLE);
mSDWiFiPacketRate = new StandardDeviation(StandardDeviation.DOUBLE);
mSDWIFIRx = new StandardDeviation(StandardDeviation.DOUBLE);
mSDWIFITx = new StandardDeviation(StandardDeviation.DOUBLE);
mSDVoltage = new StandardDeviation(StandardDeviation.DOUBLE);
}
public void Clear(){
//mLEDState = true; 상태는 초기화 되면 안된다
mLEDActivityTime = 0.0;
mLEDBrightness = 0.0;
mCPULoad = 0.0;
mCPUFrequency = 0.0;
//mGPSState = false; 상태는 초기화 되면 안된다
mGPSActivityTime = 0.0;
mCellularRx = 0.0;
mCellularTx = 0.0;
mCellularActivityTime = 0.0;
mWIFIPacketRate = 0.0;
mWIFIRx = 0.0;
mWIFITx = 0.0;
mWIFITActivityTime = 0.0;
//mAUDIOState = false; 상태는 초기화 되면 안된다
mAUDIOActivityTime = 0.0;
mCount = 0.0;
mVoltage = 0.0;
//표준편차를 구하는 개체들의 내부를 초기화 해준다.
mSDLEDBright.clear();
mSDCPULoad.clear();
mSDCPUFrequency.clear();
mSDCellularRx.clear();
mSDCellularTx.clear();
mSDWiFiPacketRate.clear();
mSDWIFIRx.clear();
mSDWIFITx.clear();
mSDVoltage.clear();
}
}
}